package com.wzw.basics.reflection;

import com.wzw.basics.test.Demo;

import java.lang.reflect.*;

/**
 * {@link Class}
 * Class类的对象表示JVM中一个类或者接口，每个java对象被加载到jvm中都会表现为一个Class类型的对象，
 * java中的数组也被映射为Class对象，所有元素类型相同且维数相同的数组都共享一个class对象，
 * 通过Class对象可以获取类或者接口中的任何信息，
 * 比如：类名、类中声明的泛型信息、类的修饰符、类的父类信息、类的接口信息、类中的任何方法信息、类中任何字段信息等等。
 *
 * 问题：
 *  1.当前类无法获取自生实际的泛型类型
 *  2.方法getGenericSuperclass只能获取其父类的类型，如果父类包含泛型就返回ParameterizedType类型。就可以获取其实际类型了
 *
 * @author Wangzhiwen
 */
public class ClassApi {

    public static void main(String[] args) {
        /*
         * 常用方法
         */
        Class<DemoExt> demoExtClass = DemoExt.class;
        // 返回当前类的以及其所有父类、父类的父类中所有public类型的字段
        Field[] publicFields = demoExtClass.getFields();

        // 当前类中所有字段（和修饰符无关），也就说不管这个字段是public还是private或者是protected，都会返回，有一点需要注意，只返回自己内部定义的字段，不包含其父类中的，这点需要注意，和getFields是有区别的。
        Field[] thisDeclaredFields = demoExtClass.getDeclaredFields();

        // 返回当前类的以及其所有父类的、父类的父类的、自己实现的接口、父接口继承的接口中的所有public类型的方法
        Method[] publicMethods = demoExtClass.getMethods();

        // 返回当前类中定义的所有方法，不管这个方法修饰符是什么类型的，注意只包含自己内部定义的方法，不包含当前类的父类或者其实现的接口中定义的。
        Method[] thisDeclaredMethods = demoExtClass.getDeclaredMethods();

        // 带有Generic前缀的都是返回泛型类型信息，当父类不是泛型时返回的其实就是Class对象，是泛型时返回的是ParameterizedType类型。二者都是Type的实现
        // 返回父类的类型信息，如果父类是泛型类型，会返回超类中泛型的详细信息
        Type genericSuperclass = demoExtClass.getGenericSuperclass();
        if (genericSuperclass instanceof ParameterizedType){
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            Type rawType = parameterizedType.getRawType();
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            Type ownerType = parameterizedType.getOwnerType();
        }
        // 返回父类类型
        Class<? super DemoExt> superclass = demoExtClass.getSuperclass();

        // 用于返回当前类中声明的泛型变量参数列表，Class类继承了java.lang.reflect.GenericDeclaration接口，上面这个方法是在GenericDeclaration接口中定义的，Class类中实现了这个接口。
        TypeVariable<Class<DemoExt>>[] typeParameters = demoExtClass.getTypeParameters();
        for (TypeVariable<Class<DemoExt>> typeParameter : typeParameters) {
            Class<DemoExt> genericDeclaration = typeParameter.getGenericDeclaration();
        }
    }

}

class DemoClass<T,K,V> {

    private String name;

    public DemoClass() {
    }

    public DemoClass(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class DemoExt extends DemoClass<String, Integer, Long> {

    private String ext;

    public DemoExt() {
        super();
    }

    public DemoExt(String ext) {
        this.ext = ext;
    }

    public String getExt() {
        return ext;
    }

    public void setExt(String ext) {
        this.ext = ext;
    }
}
